﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Smith.AMC;
using Wintellect.Threading.AsyncProgModel;

namespace MemcachedWebAppTest
{
    /// <summary>
    /// Summary description for Cache
    /// </summary>
    public class Cache : IHttpAsyncHandler
    {
        private static readonly IMemcachedClient MemcachedClient = new MemcachedClient();
        /// <summary>
        /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
        /// </summary>
        /// <value></value>
        /// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
        public void ProcessRequest(HttpContext context)
        {
            IAsyncResult ar = BeginProcessRequest(context, null, null);
            EndProcessRequest(ar);
        }

        /// <summary>
        /// Initiates an asynchronous call to the HTTP handler.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
        /// <param name="cb">The <see cref="T:System.AsyncCallback"/> to call when the asynchronous method call is complete. If <paramref name="cb"/> is null, the delegate is not called.</param>
        /// <param name="extraData">Any extra data needed to process the request.</param>
        /// <returns>
        /// An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.
        /// </returns>
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            AsyncEnumerator ae = new AsyncEnumerator();
            return ae.BeginExecute(DoProcessRequest(ae, context), cb, extraData);
        }

        /// <summary>
        /// Provides an asynchronous process End method when the process ends.
        /// </summary>
        /// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            AsyncEnumerator.FromAsyncResult(result).EndExecute(result);
        }

        private IEnumerator<int> DoProcessRequest(AsyncEnumerator ae, HttpContext context)
        {
            context.Response.ContentType = "text/plain";

            ICacheItem<string> cacheItem;
            string method = context.Request.QueryString["method"];
            string cacheKey = context.Request.QueryString["key"];
            string value = context.Request.QueryString["value"];
            switch (method ?? "GET")
            {
                case "POST":
                    cacheItem = new CacheItem<string> { CacheKey = cacheKey, LifeTime = TimeSpan.FromMinutes(20), Value = value };
                    MemcachedClient.BeginAdd(cacheItem, ae.End(), null);
                    break;
                case "GET":
                    MemcachedClient.BeginGet<string>(cacheKey ?? "dummy", ae.End(), "GET");
                    break;
                case "DELETE":
                    MemcachedClient.BeginRemove(cacheKey, ae.End(), null);
                    break;
                case "PUT":
                    cacheItem = new CacheItem<string> { CacheKey = cacheKey, LifeTime = TimeSpan.FromMinutes(20), Value = value };
                    MemcachedClient.BeginSet(cacheItem, ae.End(), null);
                    break;
            }
            yield return 1;

            try
            {
                switch (method ?? "GET")
                {
                    case "GET":
                        cacheItem = MemcachedClient.EndGet<string>(ae.DequeueAsyncResult());
                        context.Response.Write("CacheKey:");
                        context.Response.Write(cacheItem.CacheKey + "\r\n");
                        context.Response.Write("Cache Value:");
                        context.Response.Write(cacheItem.Value + "\r\n");
                        break;
                    case "POST":
                        if (MemcachedClient.EndAdd<string>(ae.DequeueAsyncResult()))
                        {
                            context.Response.Write("STORED");
                        }
                        else
                        {
                            context.Response.Write("NOT STORED - its already there?");
                        }
                        break;
                    case "PUT":
                        if (MemcachedClient.EndSet<string>(ae.DequeueAsyncResult()))
                        {
                            context.Response.Write("STORED");
                        }
                        else
                        {
                            context.Response.Write("NOT STORED - something went wrong?");
                        }
                        break;
                    case "DELETE":
                        if(MemcachedClient.EndRemove(ae.DequeueAsyncResult()))
                        {
                            context.Response.Write("DELETED");
                        }
                        else
                        {
                            context.Response.Write("Not Deleted");
                        }
                        break;
                }
            }
            catch (Exception e)
            {
                context.Response.Write(e);
            }
           
        }
    }
}